﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace Kyoh.Lib.Win32API.NetResources
{
    /// <summary>ネットワーク接続されたリソースを管理します。</summary>
	public static class WindowsNetwork
	{
		private const int StringBufferSize = 0x10000;

        /// <summary>新しいネットワークリソースに接続します。</summary>
        /// <param name="owner">オーナーウインドウのハンドル。<see cref="IntPtr.Zero"/>を指定できます。</param>
        /// <param name="netResource">接続先のリソース。</param>
        /// <param name="password">接続に使用するパスワード。</param>
        /// <param name="userName">接続に使用するユーザ名。</param>
        /// <param name="options">接続のオプション。</param>
        public static void AddConnection(IntPtr owner, ref NetResource netResource, string password, string userName, ConnectionUpdateOptions options)
        {
            WNetException.ThrowException(NativeMethods.WNetAddConnection3(owner, ref netResource, password, userName, options));
        }

        /// <summary>接続を切断します。</summary>
        /// <param name="name">ネットワーク接続名。</param>
        /// <param name="options">ネットワーク接続のオプション。</param>
        /// <param name="force">強制的に切断する場合は <c>true</c> 、それ以外の場合は <c>false</c> 。</param>
		public static void CancelConnection(string name, ConnectionUpdateOptions options, bool force)
		{
            WNetException.ThrowException(NativeMethods.WNetCancelConnection2(name, options, force));
		}

		/// <summary>特定のローカルパスに関連付けられたリモート・パスを取得します。</summary>
		public static string GetConnection(string localName)
		{
			StringBuilder strBuilder = new StringBuilder(StringBufferSize);
			uint length = (uint)StringBufferSize;
            WNetException.ThrowException(NativeMethods.WNetGetConnection(localName, strBuilder, ref length));
			return strBuilder.ToString();
		}

		/// <summary>特定パスのリソースについて、接続ユーザを取得する。</summary>
		/// <param name="target">リソースのパス（ローカル／リモート）</param>
		public static string GetUser(string target)
		{
			StringBuilder strBuilder = new StringBuilder(StringBufferSize);
			uint length = StringBufferSize;
            var code = NativeMethods.WNetGetUser(target, strBuilder, ref length);
			WNetException.ThrowException(code);
			return strBuilder.ToString();
		}

		/// <summary>ネットワークで接続されている一連のリソースを取得する</summary>
		public static NetResource[] GetResources()
		{
			return GetResources( ResourceScope.Globalnet, ResourceType.Any, ResourceUsage.All, null);
		}

		/// <summary>ネットワークで接続されている一連のリソースを取得する</summary>
		public static NetResource[] GetResources(ResourceType type, object target)
		{
			return GetResources( ResourceScope.Globalnet, type, ResourceUsage.All, target);
		}

		/// <summary>ネットワークで接続されている一連のリソースを取得する</summary>
		public static NetResource[] GetResources(ResourceScope scope, ResourceType type, ResourceUsage usage, object target)
		{
			return new List<NetResource>(EnumResource(scope, type, usage, target)).ToArray();
		}

		/// <summary>ネットワークで接続されている一連のリソースを取得する</summary>
		private static IEnumerable<NetResource> EnumResource(
			ResourceScope scope,
			ResourceType type,
			ResourceUsage usage,
			object netResource)
		{
			int count = -1;
			int size = 0x4000;
			IntPtr enumHandle = new IntPtr();
			IntPtr resultBuffer = Marshal.AllocHGlobal(size);

			// 列挙開始
            WNetException.ThrowException(NativeMethods.WNetOpenEnum(scope, type, usage, netResource, out enumHandle));
			try
			{
				bool more;
				do
				{
					// 取得する
                    var res = NativeMethods.WNetEnumResource(enumHandle, ref count, resultBuffer, ref size);
					switch (res)
					{
						case WNetConnectionResult.NoError:
							more = false;
							goto case WNetConnectionResult.MoreData;

						case WNetConnectionResult.MoreData:
							more = true;
							for (int i = 0, point = resultBuffer.ToInt32(); i < count; i++, point += Marshal.SizeOf(typeof(NetResource)))
								yield return (NetResource)Marshal.PtrToStructure(new IntPtr(point), typeof(NetResource));
							break;

						default:
							more = false;
							break;
					}
				} while (more);
			}
			finally
			{
				Marshal.FreeHGlobal(resultBuffer);
                NativeMethods.WNetCloseEnum(enumHandle);
			}
		}

	}
}
